//////////////////////////////////////////////
// File				:	CRenderer.cpp
//
// Author			:	Nick Faletra (NF)
//
// Date Created		:	12/19/2013
//////////////////////////////////////////////
#include "Renderer.h"

CRenderer::CRenderer() : m_pD3D(nullptr)
					   , m_pDevice(nullptr)
					   , m_pSprite(nullptr)
					   , m_pFont(nullptr)
					   , m_pLine(nullptr)
{
	memset(&m_PresentParams, 0, sizeof(D3DPRESENT_PARAMETERS));
}

CRenderer::~CRenderer()
{
}

bool CRenderer::Initialize(HWND hWnd, int nWidth, int nHeight, bool bWindowed, bool bVsync)
{
	if (!hWnd)
		return false;

	m_hWnd = hWnd;

	m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);

	if (!m_pD3D)
		DXERROR("Failed to Create D3D Object");

	m_PresentParams.BackBufferWidth				= nWidth;
	m_PresentParams.BackBufferHeight			= nHeight;
	m_PresentParams.BackBufferFormat			= D3DFMT_A8R8G8B8;
	m_PresentParams.BackBufferCount				= 1;
	m_PresentParams.MultiSampleType				= D3DMULTISAMPLE_NONE;
	m_PresentParams.MultiSampleQuality			= 0;
	m_PresentParams.SwapEffect					= D3DSWAPEFFECT_DISCARD;
	m_PresentParams.hDeviceWindow				= hWnd;
	m_PresentParams.Windowed					= bWindowed;
	m_PresentParams.EnableAutoDepthStencil		= false;
	m_PresentParams.Flags						= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	m_PresentParams.FullScreen_RefreshRateInHz	= D3DPRESENT_RATE_DEFAULT;
	m_PresentParams.PresentationInterval		= bVsync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;

	if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_PresentParams, &m_pDevice)))
		DXERROR("Failed to Create D3D Device");

	if (FAILED(D3DXCreateSprite(m_pDevice, &m_pSprite)))
		DXERROR("Failed to Create the Sprite object");

	if (FAILED(D3DXCreateLine(m_pDevice, &m_pLine)))
		DXERROR("Failed to Create the Line object");

	m_pLine->SetAntialias(true);
	m_pLine->SetWidth(1.f);

	return true;
}

void CRenderer::Shutdown()
{
	SAFE_RELEASE(m_pFont);
	SAFE_RELEASE(m_pLine);
	SAFE_RELEASE(m_pSprite);
	SAFE_RELEASE(m_pDevice);
	SAFE_RELEASE(m_pD3D);
}

void CRenderer::Clear(unsigned char red, unsigned char green, unsigned char blue)
{
	m_pDevice->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, red, green, blue), 1.f, 0);

	if (m_pDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
	{
		m_pLine->OnLostDevice();
		m_pSprite->OnLostDevice();
		m_pDevice->Reset(&m_PresentParams);
		m_pSprite->OnResetDevice();
		m_pLine->OnResetDevice();
	}
}

bool CRenderer::DeviceBegin()
{
	if (FAILED(m_pDevice->BeginScene()))
		DXERROR("Failed to begin device scene.");

	return true;
}

bool CRenderer::SpriteBegin()
{
	if (FAILED(m_pSprite->Begin(D3DXSPRITE_ALPHABLEND)))
		DXERROR("Failed to begin sprite scene.");

	return true;
}

bool CRenderer::LineBegin()
{
	if (FAILED(m_pLine->Begin()))
		DXERROR("Failed to begin line scene.");

	return true;
}

bool CRenderer::DeviceEnd()
{
	if (FAILED(m_pDevice->EndScene()))
		DXERROR("Failed to end device scene.");

	return true;
}

bool CRenderer::SpriteEnd()
{
	if (FAILED(m_pSprite->End()))
		DXERROR("Failed to end sprite scene.");

	return true;
}

bool CRenderer::LineEnd()
{
	if (FAILED(m_pLine->End()))
		DXERROR("Failed to end line scene.");

	return true;
}

void CRenderer::Present()
{
	m_pDevice->Present(nullptr, nullptr, nullptr, nullptr);
}

void CRenderer::ChangeDisplayParam(int nWidth, int nHeight, bool bWindowed)
{
	m_PresentParams.BackBufferFormat	= D3DFMT_A8R8G8B8;
	m_PresentParams.Windowed			= bWindowed;
	m_PresentParams.BackBufferWidth		= nWidth;
	m_PresentParams.BackBufferHeight	= nHeight;

	m_pLine->OnLostDevice();
	m_pSprite->OnLostDevice();
	m_pDevice->Reset(&m_PresentParams);
	m_pSprite->OnResetDevice();
	m_pLine->OnResetDevice();

	DWORD dwWindowStyleFlags = WS_VISIBLE;
	dwWindowStyleFlags |= bWindowed ? WS_OVERLAPPEDWINDOW : WS_POPUP;
	ShowCursor(bWindowed);

	SetWindowLong(m_hWnd, GWL_STYLE, dwWindowStyleFlags);

	if (bWindowed)
	{
		RECT rWindow;
		rWindow.left	= 0;
		rWindow.top		= 0;
		rWindow.right	= nWidth;
		rWindow.bottom	= nHeight;

		AdjustWindowRectEx(&rWindow, dwWindowStyleFlags, false, WS_EX_APPWINDOW);

		int windowWidth = rWindow.right - rWindow.left;
		int windowHeight = rWindow.bottom - rWindow.top;

		SetWindowPos(m_hWnd, HWND_TOP,
					(GetSystemMetrics(SM_CXSCREEN) >> 1) - (windowWidth >> 1),
					(GetSystemMetrics(SM_CYSCREEN) >> 1) - (windowHeight >> 1),
					windowWidth, windowHeight, SWP_SHOWWINDOW);
	}
	else
		SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}

void CRenderer::DrawRect(RECT rt, unsigned char red, unsigned char green, unsigned char blue)
{
	D3DRECT d3dRect;
	d3dRect.x1 = rt.left;
	d3dRect.y1 = rt.top;
	d3dRect.x2 = rt.right;
	d3dRect.y2 = rt.bottom;

	m_pDevice->Clear(1, &d3dRect, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, red, green, blue), 1.f, 0);
}

void CRenderer::DrawLine(int x1, int y1, int x2, int y2, unsigned char red, unsigned char green, unsigned char blue)
{
	D3DXVECTOR2 verts[2];

	verts[0].x = (float)x1;
	verts[0].y = (float)y1;
	verts[1].x = (float)x2;
	verts[1].y = (float)y2;

	m_pLine->Draw(verts, 2, D3DCOLOR_ARGB(255, red, green, blue));
}

void CRenderer::DrawText(char* szText, int x, int y, unsigned char red, unsigned char green, unsigned char blue)
{
	LPDIRECT3DSURFACE9 d3dBackBuffer = 0;

	m_pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dBackBuffer);

	HDC hdc = 0;
	d3dBackBuffer->GetDC(&hdc);

	SetTextColor(hdc, RGB(red, green, blue));
	SetBkMode(hdc, TRANSPARENT);
	TextOut(hdc, x, y, szText, (int)strlen(szText));

	d3dBackBuffer->ReleaseDC(hdc);
	SAFE_RELEASE(d3dBackBuffer);
}